package emi99

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/pkg/xhttp"
	"github.com/go-pay/xlog"
)

type Client struct {
	payUrl     string `json:"pay_url"`
	custUrl    string `json:"cust_url"`
	partnerNo  string `json:"partner_no"`
	customerNo string `json:"customer_no"` //商户编号
	device     string `json:"device"`
	privateKey string `json:"private_key"`
	hc         *xhttp.Client
	mu         sync.Mutex
}

// NewClient 初始化米久久客户端
func NewClient(payUrl, partnerNo, customerNo, device, privateKey string) (*Client, error) {
	return &Client{
		payUrl:     payUrl,
		partnerNo:  partnerNo,
		customerNo: customerNo,
		device:     device,
		privateKey: privateKey,
		hc:         xhttp.NewClient(),
	}, nil
}

// pubParamsHandle 公共参数处理
func (c *Client) pubParamsHandle(data gopay.BodyMap) (gopay.BodyMap, error) {
	dataBytes, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	dataStr := string(dataBytes)

	nonce := randomAlphanumeric(32)
	bm := make(gopay.BodyMap)
	bm.Set("charset", "UTF-8").
		Set("data", dataStr).
		Set("nonceStr", nonce).
		Set("partnerNo", c.partnerNo).
		//Set("sign", "").
		Set("signType", "RSA")

	sign, err := c.Sha256WithRsa(c.privateKey, bm)
	if err != nil {
		return nil, err
	}

	bm.Set("sign", sign)

	return bm, nil
}

// doPost 发起请求
func (c *Client) doPost(ctx context.Context, path string, data gopay.BodyMap) (bs []byte, err error) {
	if c.payUrl == "" {
		return nil, fmt.Errorf("[%w], %v", gopay.MissParamErr, "payUrl")
	}
	if c.partnerNo == "" {
		return nil, fmt.Errorf("[%w], %v", gopay.MissParamErr, "partnerNo")
	}

	param, err := c.pubParamsHandle(data)
	if err != nil {
		return nil, err
	}

	xlog.Debugf("emi99Param:%+v", param.JsonBody())

	res, bs, err := c.hc.Req(xhttp.TypeJSON).Post(c.payUrl + path).SendBodyMap(param).EndBytes(ctx)
	if err != nil {
		return nil, err
	}
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
	}
	return bs, nil
}

// randomAlphanumeric 随机生成字符串(数字加大小写字母)
func randomAlphanumeric(l int) string {
	str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	bytes := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}
